package com.scrm.server.wx.cp.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.scrm.api.wx.cp.dto.WxCustomerTagSaveOrUpdateDTO;
import com.scrm.api.wx.cp.entity.*;
import com.scrm.api.wx.cp.vo.FissionInviteConditionVO;
import com.scrm.api.wx.cp.vo.IdVO;
import com.scrm.api.wx.cp.vo.WxFissionTaskCustomerDetailH5VO;
import com.scrm.api.wx.cp.vo.WxFissionTaskCustomerDetailVO;
import com.scrm.common.exception.BaseException;
import com.scrm.common.util.JwtUtil;
import com.scrm.common.util.ListUtils;
import com.scrm.common.util.UUID;
import com.scrm.server.wx.cp.mapper.WxFissionTaskCustomerDetailMapper;
import com.scrm.server.wx.cp.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 企微应用宝-领奖信息 服务实现类
 * @author xxh
 * @since 2022-03-21
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class WxFissionTaskCustomerDetailImpl extends ServiceImpl<WxFissionTaskCustomerDetailMapper, WxFissionTaskCustomerDetail> implements IWxFissionTaskCustomerDetailService {

    @Autowired
    private IWxFissionStageService stageService;

    @Autowired
    private IWxCustomerService customerService;

    @Autowired
    private IStaffService staffService;

    @Autowired
    private IWxFissionCustomerService fissionCustomerService;

    @Autowired
    private IWxFissionTaskService fissionTaskService;

    @Override
    public WxFissionTaskCustomerDetail checkExists(String id){
        if (StringUtils.isBlank(id)) {
            return null;
        }
        WxFissionTaskCustomerDetail byId = getById(id);
        if (byId == null) {
            throw new BaseException("企微应用宝-领奖信息不存在");
        }
        return byId;
    }

    @Override
    public void initDetails(WxFissionTask task, String extCustomerId) {

        //查询全部阶段
        List<WxFissionStage> stageList = stageService.list(new QueryWrapper<WxFissionStage>().lambda()
                .eq(WxFissionStage::getExtCorpId, task.getExtCorpId())
                .eq(WxFissionStage::getTaskId, task.getId()));

        //数据入库
        List<WxFissionTaskCustomerDetail> details = stageList.stream().map(stage ->
                new WxFissionTaskCustomerDetail()
                        .setId(UUID.get32UUID()).setTaskId(task.getId())
                        .setExtCorpId(task.getExtCorpId()).setStage(stage.getStage())
                        .setExtCustomerId(extCustomerId).setHasFinish(false)
                        .setHasPrize(false).setCreatedAt(new Date())
                        .setUpdatedAt(new Date())).collect(Collectors.toList());

        saveBatch(details);
    }

    @Override
    public WxFissionTaskCustomerDetailVO translate(WxFissionTaskCustomerDetail detail) {
        WxFissionTaskCustomerDetailVO resVO = new WxFissionTaskCustomerDetailVO();
        BeanUtils.copyProperties(detail, resVO);

        resVO.setCustomer(customerService.find(detail.getExtCorpId(), detail.getExtCustomerId()));
        if (StringUtils.isNotBlank(resVO.getStaffId())) {
            resVO.setStaff(staffService.checkExists(resVO.getStaffId()));
        }

        return resVO;
    }

    @Override
    public void price(IdVO dto) {
        WxFissionTaskCustomerDetail detail = checkExists(dto.getId());
        if (!detail.getHasFinish()) {
            throw new BaseException("您未完成任务，不能兑奖！");
        }
        if (detail.getHasPrize()) {
            throw new BaseException("您已兑换过该奖励，请不要重复兑换！");
        }
//        //查这个阶段需要的人数
//        WxFissionStage stage = stageService.getOne(new QueryWrapper<WxFissionStage>().lambda()
//                .eq(WxFissionStage::getExtCorpId, detail.getExtCorpId())
//                .eq(WxFissionStage::getTaskId, detail.getTaskId())
//                .eq(WxFissionStage::getStage, detail.getStage()));
//
//        //查客户
//        List<WxFissionCustomer> customerList = fissionCustomerService.list(new QueryWrapper<WxFissionCustomer>().lambda()
//                .eq(WxFissionCustomer::getExtCorpId, detail.getExtCorpId())
//                .eq(WxFissionCustomer::getTaskId, detail.getTaskId())
//                .eq(WxFissionCustomer::getExtInviteCustomerId, detail.getExtCustomerId())
//                .eq(WxFissionCustomer::getHasFirst, true)
//                .eq(WxFissionCustomer::getHasDeleted, false)
//                .isNull(WxFissionCustomer::getPriceDetailId)
//                .orderByAsc(WxFissionCustomer::getCreatedAt));
//
//        if (ListUtils.isEmpty(customerList) || customerList.size() < stage.getNum()) {
//            throw new BaseException("邀请人数不足，无法领奖！");
//        }
//
//        //领奖消耗客户
//        List<WxFissionCustomer> priceCustomers = new ArrayList<>(stage.getNum());
//        for (Integer i = 0; i < stage.getNum(); i++) {
//            WxFissionCustomer wxFissionCustomer = customerList.get(i);
//            wxFissionCustomer.setPriceDetailId(detail.getId());
//            priceCustomers.add(wxFissionCustomer);
//        }

        detail.setHasPrize(true);
        detail.setPrizeAt(new Date());
        detail.setStaffId(JwtUtil.getUserId());
        updateById(detail);
//        fissionCustomerService.updateBatchById(priceCustomers);
    }

    @Override
    public List<WxFissionTaskCustomerDetailH5VO> getFinishDetails(FissionInviteConditionVO vo) {
        List<WxFissionTaskCustomerDetail> detailList = list(new QueryWrapper<WxFissionTaskCustomerDetail>().lambda()
                .eq(WxFissionTaskCustomerDetail::getExtCorpId, vo.getExtCorpId())
                .eq(WxFissionTaskCustomerDetail::getTaskId, vo.getTaskId())
                .eq(WxFissionTaskCustomerDetail::getExtCustomerId, vo.getExtCustomerId())
                .orderByAsc(WxFissionTaskCustomerDetail::getStage)
        );

        WxFissionTask wxFissionTask = fissionTaskService.checkExists(vo.getTaskId());

        //查询这个客户邀请的未算进完成的人数
        int successInviteNum = (int)fissionCustomerService.count(new QueryWrapper<WxFissionCustomer>().lambda()
                .eq(WxFissionCustomer::getExtCorpId, vo.getExtCorpId())
                .eq(WxFissionCustomer::getTaskId, vo.getTaskId())
                .eq(WxFissionCustomer::getExtInviteCustomerId, vo.getExtCustomerId())
                .eq(WxFissionCustomer::getHasFirst, true)
                .eq(wxFissionTask.getHasCheckDelete(), WxFissionCustomer::getHasDeleted, false)
                .isNull(WxFissionCustomer::getPriceDetailId)
        );

        //未完成且开启的只有一次
        boolean firstNoFinish = true;
        //循环拿到结果
        List<WxFissionTaskCustomerDetailH5VO> result = new ArrayList<>(detailList.size());
        for (WxFissionTaskCustomerDetail detail : detailList) {

            WxFissionTaskCustomerDetailH5VO resVO = new WxFissionTaskCustomerDetailH5VO();
            BeanUtils.copyProperties(detail, resVO);

            result.add(resVO);
            //查询阶段信息
            WxFissionStage stage = stageService.getOne(new QueryWrapper<WxFissionStage>().lambda()
                    .eq(WxFissionStage::getExtCorpId, resVO.getExtCorpId())
                    .eq(WxFissionStage::getTaskId, resVO.getTaskId())
                    .eq(WxFissionStage::getStage, resVO.getStage()));

            resVO.setFissionStage(stage);

            //处理数据
            //已兑奖的肯定是已完成
            if (resVO.getHasPrize() || resVO.getHasFinish()) {
                resVO.setIsOpen(true).setSuccessNum(stage.getNum()).setNeedNum(0).setHasFinish(true);
            } else if (successInviteNum < 0) {
                //未兑奖的
                //已经没有成功的数量了
                resVO.setIsOpen(false).setSuccessNum(0).setNeedNum(stage.getNum()).setHasFinish(false);
            }else{
                //未兑奖的，还有成功数量
                int needNum =  stage.getNum() - successInviteNum;
                resVO.setSuccessNum(successInviteNum)
                        .setNeedNum(needNum)
                        .setHasFinish(false);
                if (firstNoFinish) {
                    resVO.setIsOpen(true);
                    firstNoFinish = false;
                }else{
                    resVO.setIsOpen(false);
                }
            }
        }

        return result;
    }

    public List<WxFissionTaskCustomerDetailH5VO> getFinishDetailsOld(FissionInviteConditionVO vo) {
        List<WxFissionTaskCustomerDetail> detailList = list(new QueryWrapper<WxFissionTaskCustomerDetail>().lambda()
                .eq(WxFissionTaskCustomerDetail::getExtCorpId, vo.getExtCorpId())
                .eq(WxFissionTaskCustomerDetail::getTaskId, vo.getTaskId())
                .eq(WxFissionTaskCustomerDetail::getExtCustomerId, vo.getExtCustomerId())
                .orderByAsc(WxFissionTaskCustomerDetail::getStage)
        );

        //查询这个客户邀请的未兑奖的人数
        int successInviteNum = (int)fissionCustomerService.count(new QueryWrapper<WxFissionCustomer>().lambda()
                .eq(WxFissionCustomer::getExtCorpId, vo.getExtCorpId())
                .eq(WxFissionCustomer::getTaskId, vo.getTaskId())
                .eq(WxFissionCustomer::getExtInviteCustomerId, vo.getExtCustomerId())
                .eq(WxFissionCustomer::getHasFirst, true)
                .eq(WxFissionCustomer::getHasDeleted, false)
                .isNull(WxFissionCustomer::getPriceDetailId)
        );

        //循环拿到结果
        List<WxFissionTaskCustomerDetailH5VO> result = new ArrayList<>(detailList.size());
        for (WxFissionTaskCustomerDetail detail : detailList) {

            WxFissionTaskCustomerDetailH5VO resVO = new WxFissionTaskCustomerDetailH5VO();
            BeanUtils.copyProperties(detail, resVO);

            result.add(resVO);
            //查询阶段信息
            WxFissionStage stage = stageService.getOne(new QueryWrapper<WxFissionStage>().lambda()
                    .eq(WxFissionStage::getExtCorpId, resVO.getExtCorpId())
                    .eq(WxFissionStage::getTaskId, resVO.getTaskId())
                    .eq(WxFissionStage::getStage, resVO.getStage()));

            resVO.setFissionStage(stage);

            //处理数据
            //已兑奖的肯定是已完成
            if (resVO.getHasPrize()) {
                resVO.setIsOpen(true).setSuccessNum(stage.getNum()).setNeedNum(0).setHasFinish(true);
            } else if (successInviteNum < 0) {
                //未兑奖的
                //已经没有成功的数量了
                resVO.setIsOpen(false).setSuccessNum(0).setNeedNum(stage.getNum()).setHasFinish(false);
            }else{
                //未兑奖的，还有成功数量
                int successNum = successInviteNum > stage.getNum() ? stage.getNum(): successInviteNum;
                int needNum = successInviteNum > stage.getNum() ? 0: stage.getNum() - successInviteNum;
                successInviteNum = successInviteNum - stage.getNum();
                resVO.setIsOpen(true)
                        .setSuccessNum(successNum)
                        .setNeedNum(needNum)
                        .setHasFinish(needNum == 0);
            }
        }

        //1阶段肯定是开启
        result.get(0).setIsOpen(true);
        return result;
    }

    @Override
    public void customerUpdate(String extCorpId, String customerExtId) {
        //获取未完成的任务id
        List<String> taskIds = fissionTaskService.findUnOverTask(extCorpId);
        if (ListUtils.isEmpty(taskIds)) {
            return;
        }

        //获取这个客户影响到的任务id,这个是需要重新计算的
        List<WxFissionCustomer> list = fissionCustomerService.list(new QueryWrapper<WxFissionCustomer>().lambda()
                .select(WxFissionCustomer::getTaskId, WxFissionCustomer::getExtInviteCustomerId)
                .eq(WxFissionCustomer::getExtCorpId, extCorpId)
                .in(WxFissionCustomer::getTaskId, taskIds)
                .eq(WxFissionCustomer::getExtCustomerId, customerExtId));

        if (ListUtils.isEmpty(list)) {
            return;
        }

        //一个个任务分别算完成情况，一起算把数据量过大
        list.forEach(wxFissionCustomer -> updateFinishStatus(extCorpId, wxFissionCustomer.getTaskId(), wxFissionCustomer.getExtInviteCustomerId()));
    }

    /**
     * 计算完成情况
     * @param extCorpId
     * @param taskId
     * @param extCustomerId
     */
    @Override
    public void updateFinishStatus(String extCorpId, String taskId, String extCustomerId) {

        WxFissionTask wxFissionTask = fissionTaskService.getById(taskId);

        //可能已经被删掉了
        if (wxFissionTask == null) {
            return;
        }

        //获取这个任务的每个阶段要多少人
        Map<Integer, Integer> stageNumMap = stageService.getStageNumMap(extCorpId, taskId);

        //查询这个人没有完成的阶段，从小到大
        List<WxFissionTaskCustomerDetail> customerDetailList = list(new QueryWrapper<WxFissionTaskCustomerDetail>().lambda()
                .eq(WxFissionTaskCustomerDetail::getExtCorpId, extCorpId)
                .eq(WxFissionTaskCustomerDetail::getTaskId, taskId)
                .eq(WxFissionTaskCustomerDetail::getExtCustomerId, extCustomerId)
                .eq(WxFissionTaskCustomerDetail::getHasFinish, false)
                .orderByAsc(WxFissionTaskCustomerDetail::getStage)
        );

        //全部完成了
        if (ListUtils.isEmpty(customerDetailList)) {
            return;
        }

        //查没有算进完成任务里的客户
        List<WxFissionCustomer> customerList = fissionCustomerService.list(new QueryWrapper<WxFissionCustomer>().lambda()
                .eq(WxFissionCustomer::getExtCorpId, extCorpId)
                .eq(WxFissionCustomer::getTaskId, taskId)
                .eq(WxFissionCustomer::getExtInviteCustomerId, extCustomerId)
                .eq(WxFissionCustomer::getHasFirst, true)
                .eq(wxFissionTask.getHasCheckDelete(), WxFissionCustomer::getHasDeleted, false)
                .isNull(WxFissionCustomer::getPriceDetailId)
                .orderByAsc(WxFissionCustomer::getCreatedAt));

        //更新任务完成情况
        int i = 0;
        boolean hasFinish = true;
        for (WxFissionTaskCustomerDetail detail : customerDetailList) {

            Integer num = stageNumMap.getOrDefault(detail.getStage(), Integer.MAX_VALUE);
            //如果上一次是false了，后面的全是false
            hasFinish = hasFinish && i + num <= customerList.size() ;
            detail.setHasFinish(hasFinish);

            if (hasFinish) {
                //完成任务消耗客户
                for (int j = 0; j < num; i++,j++) {
                    WxFissionCustomer wxFissionCustomer = customerList.get(i);
                    wxFissionCustomer.setPriceDetailId(detail.getId());
                }

                //完成任务打标签
                addTag(extCorpId, taskId, detail.getStage(), extCustomerId);
            }

        }

        updateBatchById(customerDetailList);
        fissionCustomerService.updateBatchById(customerList);
    }

    /**
     * 客户完成了某个阶段的任务给它打标签
     * @param taskId
     * @param stage
     * @param extCustomerId
     */
    private void addTag(String extCorpId, String taskId, Integer stage, String extCustomerId) {

        WxFissionStage fissionStage = stageService.getOne(new QueryWrapper<WxFissionStage>().lambda()
                .eq(WxFissionStage::getExtCorpId, extCorpId)
                .eq(WxFissionStage::getTaskId, taskId)
                .eq(WxFissionStage::getStage, stage));

        List<String> tags = fissionStage.getTags();
        log.info("(应用宝)[{}]完成了任务[{}]的阶段[{}]，打上标签[{}]", extCustomerId, taskId, stage, JSON.toJSONString(tags));

        WxCustomer wxCustomer = customerService.checkExists(extCorpId, extCustomerId);

        //TODO 这个给哪个员工打标签的逻辑还有问题
        WxCustomerTagSaveOrUpdateDTO dto = new WxCustomerTagSaveOrUpdateDTO()
                .setId(wxCustomer.getId())
                .setAddTags(tags);

//        try {
//            customerService.editTag(dto);
//        } catch (WxErrorException e) {
//            log.error("(应用宝)[{}]完成了任务[{}]的阶段[{}]，打上标签[{}]失败，", extCustomerId, taskId, stage, JSON.toJSONString(tags), e);
//        }
    }
}
